/*
 * tab_search.cpp
 *
 *  Created on: 12.06.2013
 *      Author: SpirTanol
 */

#include "ui/tab_search.h"
#include "ui/table_device.h"
#include "global.h"
#include "device/search_thread.h"
#include "events/search_event.h"
#include "device/device_info.h"
#include "ui/main_window.h"
#include "ui/search_dialog.h"
#include "app_config.h"

// QT
#include <QGridLayout>
#include <QComboBox>
#include <QPushButton>
#include <QProgressBar>
#include <QLabel>
#include <QSpacerItem>
#include <QDebug>
#include <QDir>

// STD
#include <stdio.h>
//======================================================================================
TabSearch::TabSearch(MainWindow *mainWindow, QWidget *parent) : QWidget(parent), oThread(0), oMainWindow(mainWindow),
	oSearchDialog(0)
{
	QGridLayout *l = new QGridLayout(this);
	oDeviceTable = new TableDevice(&oDevices);
	l->addWidget(oDeviceTable, 0, 0);
	connect(oDeviceTable, SIGNAL(selectedDevice(DeviceInfo*)), this, SLOT(onSelectDevice(DeviceInfo*)));
	connect(oDeviceTable, SIGNAL(connectTo(DeviceInfo*)), this, SLOT(onBtnConnectClicked()));

	QWidget *w = new QWidget();
	QGridLayout *l2 = new QGridLayout(w);

	int row = 0;
	l2->addWidget(new QLabel(trUtf8("Порт:")), row, 0);

	oComboPort = new QComboBox();
	fillComboPort(oComboPort, AppConfig::i()->port());
	l2->addWidget(oComboPort, row++, 1);
	connect(oComboPort, SIGNAL(currentIndexChanged(int)), this, SLOT(onSetupChanged()));

	l2->addWidget(new QLabel(trUtf8("Скорость:")), row, 0);

	oComboSpeed = new QComboBox();
	fillComboSpeed(oComboSpeed);
	oComboSpeed->setCurrentIndex(AppConfig::i()->speedIndex());
	l2->addWidget(oComboSpeed, row++, 1);
	connect(oComboSpeed, SIGNAL(currentIndexChanged(int)), this, SLOT(onSetupChanged()));

	oBtnSearch = new QPushButton(trUtf8("Поиск"));
	l2->addWidget(oBtnSearch, row++, 0, 1, 2);
	connect(oBtnSearch, SIGNAL(clicked()), this, SLOT(onBtnSearchClicked()));

	oBtnStop = new QPushButton(trUtf8("Остановить"));
	oBtnStop->setEnabled(false);
	l2->addWidget(oBtnStop, row++, 0, 1, 2);
	connect(oBtnStop, SIGNAL(clicked()), this, SLOT(onBtnStopClicked()));

	oBtnAdd = new QPushButton(trUtf8("Добавить"));
	l2->addWidget(oBtnAdd, row++, 0, 1, 2);
	connect(oBtnAdd, SIGNAL(clicked()), this, SLOT(onBtnAddClicked()));

	oBtnConnect = new QPushButton(trUtf8("Подключиться"));
	oBtnConnect->setEnabled(false);
	l2->addWidget(oBtnConnect, row++, 0, 1, 2);
	connect(oBtnConnect, SIGNAL(clicked()), this, SLOT(onBtnConnectClicked()));

	oBtnDisconnect = new QPushButton(trUtf8("Отключиться"));
	oBtnDisconnect->setEnabled(false);
	l2->addWidget(oBtnDisconnect, row++, 0, 1, 2);
	l2->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding), row, 0, 1, 2);
	connect(oBtnDisconnect, SIGNAL(clicked()), this, SLOT(onBtnDisconnectClicked()));

	l->addWidget(w, 0, 1);

	extern const QString cgProgressStyle;
	oProgressBar = new QProgressBar();
	oProgressBar->setStyleSheet(cgProgressStyle);
	oProgressBar->setFormat("%p%");
	oProgressBar->setOrientation(Qt::Horizontal);
	oProgressBar->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	oProgressBar->setMaximum(247 * 3);
	l->addWidget(oProgressBar, 1, 0, 1, 2);

	loadFindResults();
}
//======================================================================================
TabSearch::~TabSearch()
{
	saveFindResults();

	if (oThread != 0)
		delete oThread;
	if (oSearchDialog != 0)
		delete oSearchDialog;

	while (!oDevices.isEmpty())
	{
		delete oDevices.back();
		oDevices.pop_back();
	}
}
//======================================================================================
SearchThread *TabSearch::searchThread()
{
	if (oThread == 0)
	{
		oThread = new SearchThread(this);
		connect(oThread, SIGNAL(searchEvent(SearchEvent*)), this, SLOT(onSearchEvent(SearchEvent*)));
	}

	return oThread;
}
//======================================================================================
void TabSearch::onSetupChanged()
{
	bool newSearch = (oPortIndex != oComboPort->currentIndex() ||
			oSpeedIndex != oComboSpeed->currentIndex() || searchThread()->isComplete());

	oBtnStop->setEnabled(!newSearch);
}
//======================================================================================
void TabSearch::onBtnSearchClicked()
{
	oMainWindow->disconnectFromDevice();
	searchThread()->reset();

	while (!oDevices.isEmpty())
	{
		delete oDevices.back();
		oDevices.pop_back();
	}
	oDeviceTable->clear();

	oPortIndex = oComboPort->currentIndex();
	oSpeedIndex = oComboSpeed->currentIndex();

	int portNumber = oComboPort->itemData(oPortIndex, Qt::UserRole).toInt();
	AppConfig::i()->setPort(portNumber);
	AppConfig::i()->setSpeedIndex(oSpeedIndex);

	searchThread()->setPort(portNumber);
	searchThread()->setSpeed(oComboSpeed->itemData(oSpeedIndex, Qt::UserRole).toInt());
	searchThread()->startSearch();
}
//======================================================================================
void TabSearch::onBtnStopClicked()
{
	if (!searchThread()->isRunning())
	{
		searchThread()->setPort(oComboPort->itemData(oPortIndex, Qt::UserRole).toInt());
		searchThread()->setSpeed(oComboSpeed->itemData(oSpeedIndex, Qt::UserRole).toInt());
	}
	searchThread()->toggleSearch();
}
//======================================================================================
void TabSearch::onBtnAddClicked()
{
	if (oSearchDialog == 0)
		oSearchDialog = new SearchDialog();

	if (oSearchDialog->exec() == QDialog::Accepted)
	{
		searchThread()->setPort(oComboPort->itemData(oComboPort->currentIndex(), Qt::UserRole).toInt());
		searchThread()->setSpeed(oComboSpeed->itemData(oComboSpeed->currentIndex(), Qt::UserRole).toInt());

		searchThread()->oneTest(oSearchDialog->addr(), oSearchDialog->format());
	}
}
//======================================================================================
void TabSearch::onBtnConnectClicked()
{
	searchThread()->stopSearch();

	oMainWindow->connectToDevice(oDeviceTable->currentDevice());
}
//======================================================================================
void TabSearch::onBtnDisconnectClicked()
{
	oMainWindow->disconnectFromDevice();
}
//======================================================================================
void TabSearch::onSearchEvent(SearchEvent *e)
{
	switch (e->type())
	{
	case SET_STARTED:
		oMainWindow->showMessage(trUtf8("Поиск запущен..."));
		oComboPort->setEnabled(false);
		oComboSpeed->setEnabled(false);
		oBtnSearch->setEnabled(false);
		oBtnAdd->setEnabled(false);
		oBtnConnect->setEnabled(false);
		if (searchThread()->isOneTest())
			oBtnStop->setEnabled(false);
		else
		{
			oBtnStop->setEnabled(true);
			oBtnStop->setText(trUtf8("Остановить"));
		}
	case SET_STEP:
		oProgressBar->setValue(oThread->step());
		break;
	case SET_FOUND:
		oDevices.push_back(static_cast<SearchEventFound*>(e)->deviceInfo());
		oDeviceTable->addDevice();
		break;
	case SET_STOPED:
		oMainWindow->showMessage(trUtf8("Поиск остановлен..."), 0);
		oComboPort->setEnabled(true);
		oComboSpeed->setEnabled(true);
		oBtnAdd->setEnabled(true);
		oBtnSearch->setEnabled(true);
		onSetupChanged();
		if (oBtnStop->isEnabled())
			oBtnStop->setText(trUtf8("Продолжить"));
		break;
	case SET_FINISHED:
	case SET_TEST_FINISHED:
		oComboPort->setEnabled(true);
		oComboSpeed->setEnabled(true);
		oBtnAdd->setEnabled(true);
		oBtnSearch->setEnabled(true);
		onSetupChanged();

		oMainWindow->showMessage(trUtf8("Поиск завершён..."), 0);
		break;
	case SET_ERROR:
		switch (static_cast<SearchEventError*>(e)->code())
		{
			case SearchEventError::OPEN_ERROR:
				oComboPort->setEnabled(true);
					oComboSpeed->setEnabled(true);
					oBtnAdd->setEnabled(true);
					oBtnSearch->setEnabled(true);
					onSetupChanged();

					oMainWindow->showMessage(trUtf8("Поиск остановлен. Ошибка открытия COM-порта"), 0);
				break;
		}
		break;
	}
}
//======================================================================================
void TabSearch::saveFindResults()
{
	FILE *f = fopen("../data/device_list.dat", "wb");
	if (!f) return;

	for (QVector<DeviceInfo*>::ConstIterator it = oDevices.begin(); it != oDevices.end(); ++it)
		fwrite((*it), sizeof(DeviceInfo), 1, f);

	fclose(f);
}

void TabSearch::loadFindResults()
{
	FILE *f = fopen("../data/device_list.dat", "rb");
	if (!f) return;

	while (!feof(f))
	{
		void *memDev = malloc(sizeof(DeviceInfo));
		if (!fread(memDev, sizeof(DeviceInfo), 1, f))
		{
			free(memDev);
			break;
		}
		DeviceInfo *dev = newIn<DeviceInfo>(memDev);
		oDevices.push_back(dev);
		oDeviceTable->addDevice();
	}

	fclose(f);
}
//======================================================================================
void TabSearch::onSelectDevice(DeviceInfo *dev)
{
	oBtnConnect->setEnabled(dev != 0 && dev->type() != DT_UNKOWN);
}
//======================================================================================
void TabSearch::onConnected()
{
	oBtnDisconnect->setEnabled(true);
}

void TabSearch::onDisconnected()
{
	oBtnDisconnect->setEnabled(false);
}
//======================================================================================
